
package com.test.util;

import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * 日期工具类
 * Calendar和SimpleDateFormat都是线程不安全的,可以用LocalDate
 * <p>
 * calendar.add(Calendar.YEAR,1);
 * calendar.set(Calendar.YEAR,year+1);
 * 一个用add方法,一个用set方法,假设时间是2012.02.29
 * <p>
 * 第一个返回结果是2013.02.28
 * 第二个返回结果是2013.03.01
 * <p>
 * 月份操作问题一致,建议使用add
 */
public class DateUtil {

    /**
     * MM月dd日  HH:mm格式
     */
    public final static String CHINESE_DT_NO_YEAR_AND_NO_SEC_FORMAT = "MM月dd日  HH:mm";

    /**
     * 时分格式常量
     */
    public final static String HOUR_MINUTE_FORMAT = "HH时mm分";

    /**
     * 时分秒格式常量
     */
    public static final String HOUR_MINUTE_SECOND_FORMAT = "HH:mm:ss";

    /**
     * 时间查询截止时间点
     */
    public final static String QUERY_END_TIME_FLAG = " 23:59:59";

    /**
     * 时间查询开始时间点
     */
    public final static String QUERY_START_TIME_FLAG = " 00:00:00";

    /**
     * 年
     */
    public static final String Y_SIMPLE = "yyyy";

    /**
     * 年月
     */
    public static final String YD_SIMPLE = "yyyy-MM";

    /**
     * 年月日
     */
    public static final String DT_SIMPLE = "yyyy-MM-dd";

    /**
     * 年月日
     */
    public final static String SHORT_FORMAT = "yyyyMMdd";

    /**
     * 完整时间
     */
    public static final String SIMPLE = "yyyy-MM-dd HH:mm:ss";

    /**
     * 年月日时分秒(无下划线)
     */
    public static final String DT_LONG = "yyyyMMddHHmmss";

    /**
     * 年月日时分
     */
    public static final String NO_SEC_SIMPLE = "yyyy-MM-dd HH:mm";

    /**
     * 月日时分
     */
    public static final String NO_YEAR_AND_SEC_SIMPLE = "MM-dd HH:mm";

    /**
     * 时分
     */
    public static final String TIME_NO_SEC_SIMPLE = "HH:mm";

    /**
     * 北京时间下午两点
     */
    public final static String DATE_TIME_14PM_FLAG = " 14:00:00";

    /**
     * 北京时间下午两点
     */
    public final static String DATE_TIME_15PM_FLAG = " 15:00:00";

    /**
     * 北京时间下午24点
     */
    public final static String DATE_TIME_24PM_FLAG = " 24:00前";

    /**
     * 北京時間格式:MM-dd
     */
    public final static String DATE_TIME_MM_DD_FLAG = "MM-dd";

    /**
     * MM月dd日
     */
    public final static String CHINESE_DT_NO_YEAR_FORMAT = "MM月dd日";

    private final static String DEFAULT_DATE = "1970-01-01";

    /**
     * 一天的秒数
     */
    public final static long ONE_DAY_SECONDS = 86400;

    /**
     * 日期转换成  MM月dd日  HH:mm
     *
     * @param dateString 源日期 （yyyy-MM-dd HH:mm:ss）
     * @return 转换后的日期
     */
    public static String toChineseDtNoYearNoSec(String dateString) {
        DateFormat df1 = getNewDateFormat(SIMPLE);
        DateFormat df2 = getNewDateFormat(CHINESE_DT_NO_YEAR_AND_NO_SEC_FORMAT);
        return convert(dateString, df1, df2);
    }

    /**
     * 将yyyy-MM-dd 类型的字符串转换为Date对象
     *
     * @param sDate 日期字符串对象
     * @return 日期对象
     */
    public static Date parseDateDT_SIMPLE(String sDate) {
        Date d = null;
        if ((sDate != null) && (sDate.length() == DT_SIMPLE.length())) {
            try {
                d = getFormat(DT_SIMPLE).parse(sDate);
            } catch (ParseException ex) {
                return null;
            }
        }
        return d;
    }

    /**
     * 获取日期格式
     *
     * @param format 日期格式字符串
     * @return 日期格式
     */
    private static final DateFormat getFormat(String format) {
        return new SimpleDateFormat(format);
    }

    /**
     * 获取当前天数，如果大于28，则返回28
     *
     * @return 当前天数
     */
    public static int getCurrentDay() {
        Calendar sysDate = new GregorianCalendar();
        int currentDay = sysDate.get(Calendar.DAY_OF_MONTH);
        if (currentDay > 28) {
            currentDay = 28;
        }
        return currentDay;
    }

    /**
     * 取得两个日期的间隔天数，如果除完有余数,则自然天数加1
     *
     * @param one 减数日期
     * @param two 被减数日期
     * @return 间隔天数
     */
    public static long getDiffDays(Date one, Date two) {

        if (one == null || two == null) {
            return 0L;
        }

        Calendar sysDate = new GregorianCalendar();
        sysDate.setTime(one);

        Calendar failDate = new GregorianCalendar();
        failDate.setTime(two);

        failDate.set(Calendar.HOUR_OF_DAY, sysDate.get(Calendar.HOUR_OF_DAY));
        failDate.set(Calendar.MINUTE, sysDate.get(Calendar.MINUTE));
        failDate.set(Calendar.SECOND, sysDate.get(Calendar.SECOND));
        failDate.set(Calendar.MILLISECOND, sysDate.get(Calendar.MILLISECOND));

        return (sysDate.getTimeInMillis() - failDate.getTimeInMillis()) / (24 * 60 * 60 * 1000);
    }

    /**
     * 获取两个日期之间的整数年，按周岁算法计算。
     *
     * @param one 减数日期
     * @param two 被减数日期
     * @return 间隔周年数
     */
    public static int getDiffYears(Date one, Date two) {
        if (one == null || two == null) {
            return 0;
        }

        Calendar sysDate = new GregorianCalendar();
        sysDate.setTime(one);

        Calendar failDate = new GregorianCalendar();
        failDate.setTime(two);

        // 获取年差距
        int diffYear = sysDate.get(Calendar.YEAR) - failDate.get(Calendar.YEAR);

        // 获取日月值
        int a = (sysDate.get(Calendar.MONTH) + 1) * 100 + sysDate.get(Calendar.DATE);
        int b = (failDate.get(Calendar.MONTH) + 1) * 100 + failDate.get(Calendar.DATE);

        // 计算偏移量
        int offset = (a - b) >= 0 ? 0 : -1;

        return diffYear + offset;

    }

    /**
     * 判断两个时间之间间隔月份是否在diffMonth值指定的月份之内
     *
     * @param start     起始时间
     * @param end       结束时间
     * @param diffMonth 间隔月份差值
     * @return 开始时间和结束时间间隔在指定月份内返回true，否则返回false
     */
    public static boolean getDiffMonth(Date start, Date end, int diffMonth) {
        if (start == null || end == null) {
            return false;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(start);
        calendar.add(Calendar.MONTH, diffMonth);
        if (calendar.getTime().after(end)) {
            return false;
        }
        return true;
    }

    /**
     * 获取指定月份的相差日期
     *
     * @param dt   指定日期
     * @param diff 相差的月份
     * @return 相差的日期
     */
    public static final Date getDiffDate(Date dt, int diff) {
        Calendar c = Calendar.getInstance();
        c.setTime(dt);
        c.add(Calendar.MONTH, diff);
        return c.getTime();
    }

    /**
     * 返回长日期格式（yyyyMMddHHmmss格式）
     *
     * @param date 日期
     * @return 日期字符串
     */
    public static final String longDate(Date date) {
        if (date == null) {
            return null;
        }
        return getFormat(DT_LONG).format(date);
    }

    /**
     * 获取年月日分秒格式字符串
     *
     * @param date 日期
     * @return 年月日分秒格式字符串
     */
    public static String getYearAndSecDateString(Date date) {
        return getDateString(date, getFormat(SIMPLE));
    }

    /**
     * 获取年月日日期格式字符串
     *
     * @param date 日期
     * @return 年月日日期格式字符串
     */
    public static String getNoSecDateString(Date date) {
        return getDateString(date, getFormat(NO_SEC_SIMPLE));
    }

    /**
     * 获取月日日期格式字符串
     *
     * @param date 日期
     * @return 月日日期格式字符串
     */
    public static String getMonthDayDateString(Date date) {
        return getDateString(date, getFormat(DATE_TIME_MM_DD_FLAG));
    }

    /**
     * 获取月日日期格式字符串
     *
     * @param date 日期
     * @return 月日日期格式字符串
     */
    public static String getNoYearAndSecDateString(Date date) {
        return getDateString(date, getFormat(NO_YEAR_AND_SEC_SIMPLE));
    }

    /**
     * yyyy-MM-dd
     *
     * @param date 日期
     * @return yyyy-MM-dd格式字符
     */
    public static final String dtSimpleFormat(Date date) {
        if (date == null) {
            return "";
        }
        return getFormat(DT_SIMPLE).format(date);
    }

    /**
     * HH:mm:ss
     *
     * @param date 日期
     * @return HH:mm:ss格式字符
     */
    public static final String timeNormalFormat(Date date) {
        if (date == null) {
            return "";
        }
        return getFormat(HOUR_MINUTE_SECOND_FORMAT).format(date);
    }

    /**
     * yyyy-MM
     *
     * @param date 日期
     * @return yyyy-MM格式字符
     */
    public static final String ydSimpleFormat(Date date) {
        if (date == null) {
            return "";
        }
        return getFormat(DT_SIMPLE).format(date);
    }

    /**
     * yyyy
     *
     * @param date 日期
     * @return yyyy格式字符
     */
    public static final String yearSimpleFormat(Date date) {
        if (date == null) {
            return "";
        }
        return getFormat(DT_SIMPLE).format(date);
    }

    /**
     * yyyy-MM-dd
     *
     * @param replaceStr 如果为空就返回的字符串
     * @param date       日期
     * @return yyyy-MM-dd格式字符,如果为空就返回输入字符串
     */
    public static final String dtSimpleFormatRep(Date date, String replaceStr) {
        if (date == null) {
            return replaceStr;
        }
        return getFormat(DT_SIMPLE).format(date);
    }

    /**
     * string为长类型
     *
     * @param date 字符串
     * @return 日期
     * @throws ParseException 解析异常
     */
    public static final Date stringLong2Date(String date) throws ParseException {
        if (date == null) {
            return null;
        }
        return getFormat(DT_LONG).parse(date);
    }

    /**
     * 返回日期时间（Add by Sunzy）
     *
     * @param stringDate 日期字符串
     * @return 日期
     * @throws ParseException 解析异常
     */
    public static final Date string2DateTime(String stringDate) throws ParseException {
        if (stringDate == null) {
            return null;
        }
        return getFormat(SIMPLE).parse(stringDate);
    }

    /**
     * 返回日期
     *
     * @param stringDate 日期字符串
     * @return 日期
     * @throws ParseException 解析异常
     */
    public static final Date string2Date(String stringDate) throws ParseException {
        if (stringDate == null) {
            return null;
        }
        return getFormat(DT_SIMPLE).parse(stringDate);
    }

    /**
     * 根据日期获取中国周，例如：星期一、星期日等
     *
     * @param date 源日期 （yyyy-MM-dd）
     * @return 如果异常返回空字符串
     */
    public static String dayForChineseWeek(String date) {
        try {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            Calendar c = Calendar.getInstance();
            c.setTime(format.parse(date));

            // 中文周几
            String weekDay = "";

            switch (c.get(Calendar.DAY_OF_WEEK)) {
                case 1:
                    weekDay = "日";
                    break;
                case 2:
                    weekDay = "一";
                    break;
                case 3:
                    weekDay = "二";
                    break;
                case 4:
                    weekDay = "三";
                    break;
                case 5:
                    weekDay = "四";
                    break;
                case 6:
                    weekDay = "五";
                    break;
                case 7:
                    weekDay = "六";
                    break;
                default:
                    break;
            }

            return "星期" + weekDay;

        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 日期
     *
     * @param stringDate 日期字符串
     * @return 日期
     * @throws ParseException 解析异常
     */
    public static final Date string2DateTimeByAutoZero(String stringDate) throws ParseException {
        if (stringDate == null) {
            return null;
        }
        if (stringDate.length() == 11) {
            stringDate = stringDate + "00:00:00";
        } else if (stringDate.length() == 13) {
            stringDate = stringDate + ":00:00";
        } else if (stringDate.length() == 16) {
            stringDate = stringDate + ":00";
        } else if (stringDate.length() == 10) {
            stringDate = stringDate + " 00:00:00";
        }
        return getFormat(SIMPLE).parse(stringDate);
    }

    /**
     * 获取与指定日期相差天数的日期
     *
     * @param dt    日期
     * @param idiff 差异事件
     * @return 差异后的日期
     */
    public static final Date getDiffDay(Date dt, int idiff) {
        Calendar c = Calendar.getInstance();
        c.setTime(dt);
        c.add(Calendar.DAY_OF_MONTH, idiff);
        return c.getTime();
    }

    /**
     * 获取与指定日期相差的小时日期
     *
     * @param dt    日期
     * @param idiff 差异小时
     * @return 差异后的日期
     */
    public static final Date getDiffHour(Date dt, int idiff) {
        Calendar c = Calendar.getInstance();
        c.setTime(dt);
        c.add(Calendar.HOUR_OF_DAY, idiff);
        return c.getTime();
    }

    /**
     * 将yyyy-MM-dd 类型的字符串转换为Date对象
     *
     * @param sDate 日期字符串对象
     * @return 日期对象
     */
    public static Date parseDateEnd(String sDate) {
        Date d = null;
        d = DateUtil.parseDateDT_SIMPLE(sDate);
        if (d != null) {
            d = DateUtil.addDays(d, 1);
        }
        return d;
    }

    /**
     * 将yyyy-MM-dd 类型的字符串转换为Date对象
     *
     * @param sDate 日期字符串对象
     * @return 日期对象
     */
    public static Date parseDateShortFormat(String sDate) {
        Date d = null;

        if ((sDate != null) && (sDate.length() == SHORT_FORMAT.length())) {
            try {
                d = getFormat(SHORT_FORMAT).parse(sDate);
            } catch (ParseException ex) {
                return null;
            }
        }

        return d;
    }

    /**
     * 获取输入日期月份的相差日期
     *
     * @param dt    日期
     * @param idiff 差异事件
     * @return 差异后的日期字符串
     */
    public static final String getDiffMon(Date dt, int idiff) {
        Calendar c = Calendar.getInstance();
        c.setTime(dt);
        c.add(Calendar.MONTH, idiff);
        return dtSimpleFormat(c.getTime());
    }

    /**
     * 判断当前日期是星期几
     *
     * @param pTime 修要判断的时间
     * @return 星期几的整数值
     */
    public static int dayForWeek(String pTime) {
        int dayForWeek = 0;
        try {
            SimpleDateFormat format = new SimpleDateFormat(DT_SIMPLE);
            Calendar c = Calendar.getInstance();
            c.setTime(format.parse(pTime));

            if (c.get(Calendar.DAY_OF_WEEK) == 1) {
                dayForWeek = 7;
            } else {
                dayForWeek = c.get(Calendar.DAY_OF_WEEK) - 1;
            }
            return dayForWeek;
        } catch (Exception ex) {
            return 0;
        }
    }

    /**
     * 获取月日日期格式字符串
     *
     * @param date 日期
     * @return 月日日期格式字符串
     */
    public static String getChineseNoYearDateString(Date date) {
        return getDateString(date, getFormat(CHINESE_DT_NO_YEAR_FORMAT));
    }

    /**
     * 获取指定年份的相差日期
     * <p>
     * 例如：当前日期2014-10-28日，向前推5年即 2009-1-1日
     * </p>
     *
     * @param dt   指定日期
     * @param diff 相差的年份
     * @return 相差的日期
     */
    public static final Date getDiffYearFirstDate(Date dt, int diff) {
        Calendar c = Calendar.getInstance();
        c.setTime(dt);
        c.add(Calendar.YEAR, diff);
        c.set(c.get(Calendar.YEAR), 0, 1, 0, 0, 0);
        return c.getTime();
    }

    /**
     * 获取指定相差年份
     * <p>
     * 例如：当前日期2014-10-28日，向前推5年即 2009-10-28日
     * </p>
     *
     * @param dt   指定日期
     * @param diff 相差的年份
     * @return 相差的日期
     */
    public static final Date getDiffYearDate(Date dt, int diff) {
        Calendar c = Calendar.getInstance();
        c.setTime(dt);
        c.add(Calendar.YEAR, diff);
        return c.getTime();
    }

    /**
     * isSameYear
     *
     * @param date1
     * @param date2
     * @return
     */
    public static boolean isSameYear(Date date1, Date date2) {
        if (date1 == null || date2 == null) {
            return false;
        }
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(date1);
        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(date2);

        return cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR);
    }

    /**
     * 比较两个日期大小
     *
     * @param c1
     * @param c2
     * @param desc max/min
     * @return
     */
    public static Date compareDate(Date c1, Date c2, String desc) {
        long tTime1 = c1.getTime();
        long tTime2 = c2.getTime();
        long result = tTime1 - tTime2;
        if (result < 0) {// c1 早于 c2
            if ("min".equals(desc)) {
                return c1;
            } else {
                return c2;
            }
        } else if (result == 0) {// c1 = c2
            return c1;
        } else {// c1 大于 c2
            if ("min".equals(desc)) {
                return c2;
            } else {
                return c1;
            }
        }
    }

    /**
     * date2Calendar
     *
     * @param date
     * @return
     */
    public static Calendar date2Calendar(Date date) {
        Calendar tCalendar = Calendar.getInstance();
        if (date == null) {
            return tCalendar;
        }
        tCalendar.setTime(date);
        return tCalendar;
    }

    /**
     * 取年度差
     *
     * @param one
     * @param two
     * @return
     */
    public static int yearDiff(Date one, Date two) {
        if (one == null || two == null) {
            return 0;
        }

        Calendar sysDate = new GregorianCalendar();
        sysDate.setTime(one);

        Calendar failDate = new GregorianCalendar();
        failDate.setTime(two);

        // 获取年差距
        int diffYear = sysDate.get(Calendar.YEAR) - failDate.get(Calendar.YEAR);

        return diffYear;
    }

    /**
     * isSameDay
     *
     * @param dateA
     * @param dateB
     * @return
     */
    public static boolean isSameDay(Date dateA, Date dateB) {
        if (dateA == null || dateB == null) {
            return false;
        }
        Calendar calDateA = Calendar.getInstance();
        calDateA.setTime(dateA);

        Calendar calDateB = Calendar.getInstance();
        calDateB.setTime(dateB);

        return calDateA.get(Calendar.YEAR) == calDateB.get(Calendar.YEAR)
                && calDateA.get(Calendar.MONTH) == calDateB.get(Calendar.MONTH)
                && calDateA.get(Calendar.DAY_OF_MONTH) == calDateB.get(Calendar.DAY_OF_MONTH);
    }

    /**
     * 根据时间戳格式化时间
     *
     * @param time 时间戳
     * @return yyyy-MM-dd
     */
    public static String formatDateFromTimestamp(long time) {
        try {
            SimpleDateFormat format = new SimpleDateFormat(DT_SIMPLE);

            return format.format(time);
        } catch (Exception e) {
            return DEFAULT_DATE;
        }
    }

    public static DateFormat getNewDateFormat(String pattern) {
        DateFormat df = new SimpleDateFormat(pattern);

        df.setLenient(false);
        return df;
    }

    public static String getDateString(Date date) {
        DateFormat df = getNewDateFormat(SHORT_FORMAT);

        return df.format(date);
    }

    public static String getDateString(Date date, DateFormat dateFormat) {
        if (date == null || dateFormat == null) {
            return null;
        }

        return dateFormat.format(date);
    }

    public static String convert(String dateString, DateFormat formatIn, DateFormat formatOut) {
        try {
            Date date = formatIn.parse(dateString);

            return formatOut.format(date);
        } catch (ParseException e) {
            return "";
        }
    }

    public static Date addDays(Date date1, long days) {
        return addSeconds(date1, days * ONE_DAY_SECONDS);
    }

    /**
     * @param date1
     * @param secs
     * @return
     */
    public static Date addSeconds(Date date1, long secs) {
        return new Date(date1.getTime() + (secs * 1000));
    }

    /**
     * 获取两个日期之间相隔的秒数,
     *
     * @param fromDate 开始日期都变了
     * @param toDate   结束日期
     * @return 两个日期之间相隔的秒
     */
    public static double getSecondSpan(Date fromDate, Date toDate) {

        long intervalMilli = toDate.getTime() - fromDate.getTime();
        return (intervalMilli * 1.0 / (1000));
    }

    /**
     * 获取本周的开始时间
     *
     * @return
     */
    public static Date getBeginDayOfWeek() {
        Date date = new Date();
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int dayofweek = cal.get(Calendar.DAY_OF_WEEK);
        if (dayofweek == 1) {
            dayofweek += 7;
        }
        cal.add(Calendar.DATE, 2 - dayofweek);
        return getDayStartTime(cal.getTime());
    }

    /**
     * 获取本周的结束时间
     *
     * @return
     */
    public static Date getEndDayOfWeek() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getBeginDayOfWeek());
        cal.add(Calendar.DAY_OF_WEEK, 6);
        Date weekEndSta = cal.getTime();
        return getDayEndTime(weekEndSta);
    }

    //获取某个日期的开始时间
    public static Timestamp getDayStartTime(Date d) {
        Calendar calendar = Calendar.getInstance();
        if (null != d) {
            calendar.setTime(d);
        }
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return new Timestamp(calendar.getTimeInMillis());
    }

    //获取某个日期的结束时间
    public static Timestamp getDayEndTime(Date d) {
        Calendar calendar = Calendar.getInstance();
        if (null != d) {
            calendar.setTime(d);
        }
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 23, 59, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return new Timestamp(calendar.getTimeInMillis());
    }

    //获取昨天的日期 yyyy-MM-dd
    public static String getYesterToday() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, -1);
        Date d = cal.getTime();
        SimpleDateFormat sp = new SimpleDateFormat(DT_SIMPLE);
        String yesterday = sp.format(d);
        return yesterday;
    }
}

